<?php

namespace nabu\libs\validations;

defined('NABU') || exit;

// Valida los campos de un formulario.
class validations {
  private $route;
  private $field;
  private $min;
  private $max;
  private $value;

  // Define la ruta para mostrar mensajes sobre campos inválidos.
  public function __construct(string $route) {
    $this -> route = $route;
  }

  // Muestra errores fatales.
  private function errors(string $error) {
    $GLOBALS['messages'] -> errors($error, 400);
  }

  // Almacena mensajes sobre campos inválidos.
  private function add_message(string $message) {
    $GLOBALS['messages'] -> add_message($message);
  }

  // Elimina espacios sobrantes y de principio y fin.
  private function trim_all(string $input) {
    return trim(preg_replace('/\s+/', ' ', $input));
  }

  // Valida la longitud de un 'string'.
  private function string_lenght() {
    $lenght = strlen($this -> value);

    if ($lenght > $this -> max || $lenght < $this -> min)
      $this -> add_message("El campo '" . $this -> field . "' no respeta los límites establecidos");
  }

  // Valida si un campo es una dirección de correo electrónico
  // y si el dominio pertenece a la Universidad de Guanajuato.
  private function validate_email() {
    $email = $this -> value;

    if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
      if (!str_ends_with($email, '@ugto.mx'))
        $this -> add_message('Registrate con tu dirección de correo electrónico institucional de la Universidad de Guanajuato');
      }
    else
      $this -> add_message("El campo '" . $this -> field . "' contiene una dirección de correo electrónico no válido");
    }

  // Valida si dos datos son iguales.
  private function validate_equal($foo) {
    if ($this -> value !== $foo)
      $this -> add_message("El campo '" . $this -> field . "' no coincide");
  }

  // Valida si un campo contiene espacios.
  private function validate_spaces() {
    if (!ctype_graph($this -> value))
      $this -> add_message("El campo '" . $this -> field . "' contiene espacios");
  }

  // Valida si los archivos provienen de la variable global '$_FILE'.
  private function not_file($file) {
    return !is_array($file) || empty($file['name']);
  }

  // Valida el tamaño y el formato de una imagen.
  private function validate_image() {
    $size = $this -> value['size'];

    if ($size > NABU_DEFAULT['image_size'] || $size <= 0) {
      $this -> add_message('Por favor elija una imagen de diferente peso');
      return false;
    }

    $image_formats = explode(',', NABU_DEFAULT['image_formats']);

    foreach ($image_formats as $format)
      if (trim($format) == $this -> value['type'])
        return true;

    $this -> add_message('Formato de imagen inválido');
  }

  // Valida y selecciona los campos de un formulario;
  //@return un array asociativo con campos validados.
  public function validate_form(array $form, array $options) {
    $data = array();

    foreach ($options as $option) {
      if (!is_array($option))
        $this -> errors('The validation options are not an array');

      if (empty($option[0]) || !is_string($option[0]))
        $this -> errors('Not found field name');

      if (empty($option['min']) || !is_int($option['min']))
        $option['min'] = 1;

      if (empty($option['max']) || !is_int($option['max']))
        $option['max'] = 255;

      $this -> field = $option[0];     // Nombre del campo.
      $this -> min   = $option['min']; // Longitud o tamaño mínimo del campo.
      $this -> max   = $option['max']; // Longitud o tamaño máximo del campo.

      // Define si un campo es obligatorio (default: false).
      $exist = empty($option['exist']) ? false : true;

      // Tipo de dato del campo (default: string).
      $type = empty($option['type']) ? 'string' : $option['type'];

      // Valida si un campo es obligatorio u opcional.
      if ($exist) {
        if (empty($form[$this -> field])) {
          $this -> add_message("El campo '" . $this -> field . "' es obligatorio");
          continue;
        }

        if ($type == 'image' && $this -> not_file($form[$this -> field])) {
          $this -> add_message("El campo '" . $this -> field . "' requiere obligatoriamente de un archivo de imagen");
          continue;
        }
      }
      else {
        if (empty($form[$this -> field]))
          continue;

        if ($type == 'image' && $this -> not_file($form[$this -> field]))
          continue;
      }

      $this -> value = $form[$this -> field];

      // Selecciona el tipo de limpieza de espacios.
      if (!empty($option['trim_all']))
        $this -> value = $this -> trim_all($form[$this -> field]);

      if (!empty($option['trim']))
        $this -> value = trim($form[$this -> field]);

      // Realiza acciones en base a 'type'.
      if ($type == 'string') {
        $this -> string_lenght();

        if (!empty($option['is_email']))
          $this -> validate_email();
      }
      elseif ($type == 'image')
          $this -> validate_image();
      else
          $this -> errors("Invalid '" . $type . "' data type");

      // Validación de datos iguales.
      if (!empty($option['equal']) && is_array($option['equal'])) {
        if ($option['equal'][0]) {
          if (empty($option['equal'][1]))
            $option['equal'][1] = null;

          $this -> validate_equal($option['equal'][1]);
        }
      }

      // Validación de espacios.
      if (!empty($option['not_spaces']) && $type != 'image')
        $this -> validate_spaces();

      $data[$this -> field] = $this -> value;
    }

    $GLOBALS['messages'] -> message_exists($this -> route);

    return $data;
  }

  public function __destruct() {
    $this -> value = null;
  }
}
